/*
 * id3_defs.h
 * This file is part of trypsyndsp
 *
 * Copyright (C) 2012 - Luke William Westby
 *
 * trypsyndsp is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * trypsyndsp is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with trypsyndsp. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef ID3_DEFS_H
#define ID3_DEFS_H

#include "trypsyn_dsp.h"

/* -------------------------------------------------------------------------- *
 * id3 header structure
 * holds info for standard id3v2 header feild. value from sync_header_size must
 * be unsynced into header_size inorder to obtain standard binary-format value.
 * bitfeilds are defined by preprocessor for header flags.
 * -------------------------------------------------------------------------- */

typedef struct _trypsyn_id3_header {
	trypsyn_uint8_t identifier[4];			// "ID3\0"
	trypsyn_uint8_t major_version;			// ex. if ID3v2.4, 0x04
	trypsyn_uint8_t revision;				// currently 0x00, but who knows
	trypsyn_uint8_t flags;					// %abcd0000
	trypsyn_syncint32_t sync_header_size;	// synchsafe int, must be decoded
	trypsyn_uint32_t header_size;			// store decoded size here
} trypsyn_id3_header;

#define TRYPSYN_ID3_HEADER_FLAGS_MASK 0xF0		// 0babcd0000
#define TRYPSYN_ID3_HEADER_FLAGS_UNSYNC 0x80	// a
#define TRYPSYN_ID3_HEADER_FLAGS_XHEADER 0x40	// b
#define TRYPSYN_ID3_HEADER_FLAGS_EXP 0x20		// c
#define TRYPSYN_ID3_HEADER_FLAGS_FOOTER 0x10	// d

/* -------------------------------------------------------------------------- *
 * extended header structure
 * hold info from extended id3v2 header if it exists. determine this from
 * header flags and TRYPSYN_ID3_HEADER_FLAGS_XHEADER mask. same deal about
 * syncsafe size. xheader flag bitfields are defined for preprocessor.
 * -------------------------------------------------------------------------- */

typedef struct _trypsyn_id3_xheader {
	trypsyn_syncint32_t sync_xheader_size;	// synchsafe size
	trypsyn_uint32_t xheader_size;			// unsync here
	trypsyn_uint8_t n_flag_bytes;			// size of flags, 0x01
	trypsyn_uint8_t xflags;					// 0b0bcd0000
} trypsyn_id3_xheader;

#define TRYPSYN_ID3_XHEADER_FLAGS_MASK 0x70			// 0b0bcd0000
#define TRYPSYN_ID3_XHEADER_FLAGS_TAGISUPDATE 0x40	// b
#define TRYPSYN_ID3_XHEADER_FLAGS_CRC 0x20			// c
#define TRYPSYN_ID3_XHEADER_FLAGS_RESTRICT 0x10		// d

/* -------------------------------------------------------------------------- *
 * id3 footer structure
 * does the same thing as header, but identifier is "3DI" instead of "ID3", so
 * no new flag masks are defined. the footer is only present if
 * TRYPSYN_ID3_HEADER_FLAGS_FOOTER is set. if not, no footer exists and padding
 * may be present so watch out for 0x00 bytes
 * -------------------------------------------------------------------------- */

typedef struct _trypsyn_id3_footer {
	trypsyn_uint8_t identifier[4];			// "3DI\0"
	trypsyn_uint8_t major_version;
	trypsyn_uint8_t revision;
	trypsyn_uint8_t flags;
	trypsyn_syncint32_t sync_footer_size;
	trypsyn_uint32_t footer_size;
} trypsyn_id3_footer;

/* -------------------------------------------------------------------------- *
 * frame header structure
 * holds general information about frames before encountering frame-type
 * specific bitfeilds. use this information about how to proceed in reading
 * the remainder of ther frame. same deal about the synced size int and flag
 * masks.
 * -------------------------------------------------------------------------- */

typedef struct _trypsyn_id3_frame_header_v2 {
	trypsyn_uint8_t identifier[4];			// three chars, A-Z
	trypsyn_uint32_t frame_size;			// 24-bit
} trypsyn_id3_frame_header_v2;

typedef struct _trypsyn_id3_frame_header_v4 {
	trypsyn_uint8_t identifier[5];			// four chars, A-Z
	trypsyn_syncint32_t sync_frame_size;	// 32-bit synchsafe
	trypsyn_uint32_t frame_size;			// unsync here
	trypsyn_uint16_t flags;					// %0bcd0000 0h00kmnp
} trypsyn_id3_frame_header_v4;

#define TRYPSYN_ID3_FRAME_V4_FLAGS_MASK 0x704F  // %0bcd0000 0h00kmnp
#define TRYPSYN_ID3_FRAME_V4_TAGPRES 0x4000		// b
#define TRYPSYN_ID3_FRAME_V4_FILEPRES 0x2000	// c
#define TRYPSYN_ID3_FRAME_V4_RDONLY 0x1000		// d
#define TRYPSYN_ID3_FRAME_V4_GROUPID 0x0040		// h
#define TRYPSYN_ID3_FRAME_V4_COMPRESS 0x008		// k
#define TRYPSYN_ID3_FRAME_V4_ENCRYPT 0x0004		// m
#define TRYPSYN_ID3_FRAME_V4_UNSYNC 0x0002		// n
#define TRYPSYN_ID3_FRAME_V4_DATALEN 0x0001		// p

/* -------------------------------------------------------------------------- *
 * structure to hold data for text frames
 * a frame is a text frame if trypsyn_id3_frame_header.identifier begins with
 * the character 'T'. An encoding byte instructs how to read or parse the data
 * which can then be pointed to by 'data'.
 * -------------------------------------------------------------------------- */

typedef struct _trypsyn_id3_text_frame {
	trypsyn_uint8_t encoding;				// see masks below
	char *data;								// data within, of undetermined fmt
} trypsyn_id3_text_frame;

#define TRYPSYN_ID3_TENC_ISO88591 0x00	// western, 0x00
#define TRYPSYN_ID3_TENC_UTF16 0x01		// 16-bit unicode, byte order mark, 0x0000
#define TRYPSYN_ID3_TENC_UTF16BE 0x02	// 16-bit unicode, big-endian, 0x0000
#define TRYPSYN_ID3_TENC_UTF8 0x03		// 8-bit unicode, 0x00

/* -------------------------------------------------------------------------- *
 * typical text frames are defined in a lookup table here for easy pattern
 * matching and decision making
 * -------------------------------------------------------------------------- */

static const char trypsyn_id3_v4_std_frames[5][5] =
{
	"TIT2\0",		// title of track
	"TOPE\0",		// artist, option 1
	"TPE1\0",		// artist, option 2
	"TALB\0",		// album
	"TCON\0"		// genre
};

#endif
